#include "CalculatorTest.h"

#define EPSILON 1.11e-16

CPPUNIT_TEST_SUITE_REGISTRATION(CalculatorTest);

void CalculatorTest::setUp(){
    c1 = new Calculator();
    c2 = new Calculator();
    c3 = new Calculator();
    c4 = new Calculator();
    c5 = new Calculator();
    c6 = new Calculator();
    c7 = new Calculator();
    c8 = new Calculator();
    c9 = new Calculator();
    c10 = new Calculator();
}

void CalculatorTest::tearDown() {
    delete c1;
    delete c2;
    delete c3;
    delete c4;
    delete c5;
    delete c6;
    delete c7;
    delete c8;
    delete c9;
    delete c10;
}

void CalculatorTest::additionTest(){
    c1->setInput("1+2");
    c2->setInput("1.2+2.9");
    c3->setInput("1+9+3");
    c4->setInput("1.258+3.69+10.25");
    c5->setInput("1.0+2.963+3.141592+788");
    c6->setInput("-1+0.5");
    c7->setInput("2.9+-3.6");
    c8->setInput("-0+0");
    c9->setInput("-1.1+0");
    c10->setInput("11+-0");
    
    CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(4.1, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(13.0, c3->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(15.198, c4->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(795.105, c5->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.5, c6->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.7, c7->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c8->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.1, c9->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(11.0, c10->calculate(), EPSILON);
}

void CalculatorTest::subtractionTest(){
    c1->setInput("2-1");
    c2->setInput("1.2-2.9");
    c3->setInput("1-9-3");
    c4->setInput("100.258-3.69-10.25");
    c5->setInput("1.0-2.963-3.141592-788");
    c6->setInput("-1-0.5");
    c7->setInput("2.9--3.6");
    c8->setInput("-0-0");
    c9->setInput("-1.1-0");
    c10->setInput("11--0");

    CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.7, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.0, c3->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(86.318, c4->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-793.105, c5->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.5, c6->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(6.5, c7->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c8->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.1, c9->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(11.0, c10->calculate(), EPSILON);
}

void CalculatorTest::multiplyTest(){
    c1->setInput("1*2");
    c2->setInput("1.2*2.9");
    c3->setInput("1*9*3");
    c4->setInput("1.258*3.69*10.25");
    c5->setInput("1.0*2.963*3.141592*788");
    c6->setInput("1*2.78*0");
    c7->setInput("2.9*-3.6");
    c8->setInput("-0*0");
    c9->setInput("-1.1*0");
    c10->setInput("11*-0");

    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(3.48, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(27.0, c3->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(47.5807, c4->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(7335.13, c5->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c6->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.44, c7->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c8->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c9->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c10->calculate(), EPSILON);
}

void CalculatorTest::divisionTest(){
    c1->setInput("1/2");
    c2->setInput("1.2/2.9");
    c3->setInput("1/9/3");
    c4->setInput("1.258/3.69/10.25");
    c5->setInput("1.0/2.963/3.141592/788");
    c6->setInput("1/2.78/0");
    c7->setInput("-1/2.78/0");

    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.41379310344828, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.03703703703703, c3->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.03326062528918, c4->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.00013633028690, c5->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(std::numeric_limits<double>::infinity(), c6->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-std::numeric_limits<double>::infinity(), c7->calculate(), EPSILON);
}

void CalculatorTest::powerTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::factorialTest(){
    c1->setInput("0!");
    c2->setInput("8!");
    c3->setInput("-1!");

    CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(40320.0, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_THROW(c3->calculate(), std::exception);
}

void CalculatorTest::minTest(){
    c1->setInput("min(1, 2)");
    c2->setInput("min(2, 1)");
    c3->setInput("min(9, 65, 3, 2, 3.21)");
    c4->setInput("min(2.5, 2.319, 2.32)");

    CPPUNIT_ASSERT_EQUAL(1.0, c1->calculate());
    CPPUNIT_ASSERT_EQUAL(1.0, c2->calculate());
    CPPUNIT_ASSERT_EQUAL(2.0, c3->calculate());
    CPPUNIT_ASSERT_EQUAL(2.319, c4->calculate());
}

void CalculatorTest::maxTest(){
    c1->setInput("max(1, 2)");
    c2->setInput("max(2, 1)");
    c3->setInput("max(9, 65, 3, 2, 3.21)");
    c4->setInput("max(2.5, 2.319, 2.32)");

    CPPUNIT_ASSERT_EQUAL(2.0, c1->calculate());
    CPPUNIT_ASSERT_EQUAL(2.0, c2->calculate());
    CPPUNIT_ASSERT_EQUAL(65.0, c3->calculate());
    CPPUNIT_ASSERT_EQUAL(2.5, c4->calculate());
}

void CalculatorTest::logTest(){
    c1->setInput("log(10)");
    c2->setInput("log(101)");
    c3->setInput("log(1)");
    c4->setInput("log(0)");
    c5->setInput("log(-0.5)");
    c6->setInput("log(10, 2)");
    c7->setInput("log(101, 2)");
    c8->setInput("log(1, 2)");
    c9->setInput("log(0, 2)");
    c10->setInput("log(-0.5, 2)");

    CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, c1->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0043213737826, c2->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c3->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-std::numeric_limits<double>::infinity(), c4->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-std::numeric_limits<double>::infinity(), c5->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(3.3219280948873, c6->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(6.6582114827518, c7->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, c8->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-std::numeric_limits<double>::infinity(), c9->calculate(), EPSILON);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-std::numeric_limits<double>::infinity(), c10->calculate(), EPSILON);
}

void CalculatorTest::rootTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::sinTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::cosTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::tanTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::cotTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::sinhTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::coshTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::tanhTest(){
    CPPUNIT_FAIL("Not implemented.");
}

void CalculatorTest::cothTest(){
    CPPUNIT_FAIL("Not implemented.");
}
